﻿using System;
using System.Drawing;
using System.Windows;
using System.Windows.Media.Imaging;
using iTunesLib;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using System.Diagnostics;

namespace iControl.Windows
{
	/// <summary>
	/// Interaction logic for Window1.xaml
	/// </summary>
	public partial class MainWindow: Window
	{
		#region Variable Declaration
		private DispatcherTimer _HidingTimer;
		private Storyboard _FadeInStoryBoard;
		private Storyboard _FadeOutStoryBoard;
		private VisibilityStatusEnum _VisibilityStatus;
		private SettingsWindow _SettingsWindow;
		private QuickSelectWindow _QuickSelectWindow;
        private AboutWindow _AboutWindow;
        private static bool _ClosingApplication;
        private System.Windows.Forms.NotifyIcon mainNotifer;
        private System.Windows.Forms.ContextMenuStrip mnuNotifier;
        private System.Windows.Forms.ToolStripMenuItem mnuExit;
        private System.Windows.Forms.ToolStripMenuItem mnuAbout;
        private System.Windows.Forms.ToolStripMenuItem mnuSettings;
        private System.Windows.Forms.ToolStripMenuItem mnuPlayPause;
        private System.Windows.Forms.ToolStripMenuItem mnuStop;
        private System.Windows.Forms.ToolStripMenuItem mnuNextTrack;
        private System.Windows.Forms.ToolStripMenuItem mnuPreviousTrack;
        private System.Windows.Forms.ToolStripMenuItem mnuShowITunes;
        private System.Windows.Forms.ToolStripSeparator mnuSeparator1;
        private System.Windows.Forms.ToolStripSeparator mnuSeparator2;
        private System.Windows.Forms.ToolStripSeparator mnuSeparator3;
		#endregion

		#region Enum Declaration
		private enum VisibilityStatusEnum
		{
			Showing,
			Visible,
			Hiding,
			Hidden,
			ForceHiding
		}
		#endregion

		#region Constructor
		public MainWindow()
		{
			InitializeComponent();

			#region Initializing Hiding Timer
			_HidingTimer = new DispatcherTimer();
			_HidingTimer.Interval = TimeSpan.FromSeconds(Settings.DefaultInstance.ShowDuration);
			_HidingTimer.Tick += new EventHandler(HidingTimer_Elapsed);
			#endregion

			#region Initializing Fade-In Animation
			var fadeInAnimation = new DoubleAnimation();
			fadeInAnimation.To = 1;
			fadeInAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Settings.DefaultInstance.FadeInDuration));

			Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(Window.OpacityProperty));

			_FadeInStoryBoard = new Storyboard();
			_FadeInStoryBoard.Children.Add(fadeInAnimation);
			_FadeInStoryBoard.Completed += new EventHandler(FadeInStoryBoard_Completed);
			#endregion

			#region Initializing Fade-Out Animation
			DoubleAnimation fadeOutAnimation = new DoubleAnimation();
			fadeOutAnimation.To = 0;
			fadeOutAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Settings.DefaultInstance.FadeOutDuration));

			Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath(Window.OpacityProperty));

			_FadeOutStoryBoard = new Storyboard();
			_FadeOutStoryBoard.Children.Add(fadeOutAnimation);
			_FadeOutStoryBoard.Completed += new EventHandler(FadeOutStoryBoard_Completed);
			#endregion

			#region Initializing Controller
			Controller.DefaultInstance.NewCommandReceived += new EventHandler<NewCommandReceivedEventArgs>(Controller_NewCommandReceived);
			#endregion

            #region Initializing Notify Icon
            mnuNotifier = new System.Windows.Forms.ContextMenuStrip();
            mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
            mnuExit = new System.Windows.Forms.ToolStripMenuItem();
            mnuNextTrack = new System.Windows.Forms.ToolStripMenuItem();
            mnuPlayPause = new System.Windows.Forms.ToolStripMenuItem();
            mnuPreviousTrack = new System.Windows.Forms.ToolStripMenuItem();
            mnuSeparator1 = new System.Windows.Forms.ToolStripSeparator();
            mnuSeparator2 = new System.Windows.Forms.ToolStripSeparator();
            mnuSettings = new System.Windows.Forms.ToolStripMenuItem();
            mnuShowITunes = new System.Windows.Forms.ToolStripMenuItem();
            mnuStop = new System.Windows.Forms.ToolStripMenuItem();
            mnuSeparator3 = new System.Windows.Forms.ToolStripSeparator();

            mnuAbout.Text = Properties.Resources.MainWindow_AboutMenuText;
            mnuAbout.Click += new EventHandler(mnuAbout_Click);

            mnuExit.Text = Properties.Resources.MainWindow_ExitMenuText;
            mnuExit.Click += new EventHandler(mnuExit_Click);

            mnuNextTrack.Text = Properties.Resources.MainWindow_NextTrackMenuText;
            mnuNextTrack.Click += new EventHandler(mnuNextTrack_Click);

            mnuPlayPause.Text = Properties.Resources.MainWindow_PlayPauseMenuText;
            mnuPlayPause.Click += new EventHandler(mnuPlayPause_Click);

            mnuPreviousTrack.Text = Properties.Resources.MainWindow_PreviousTrackMenuText;
            mnuPreviousTrack.Click += new EventHandler(mnuPreviousTrack_Click);

            mnuSettings.Text = Properties.Resources.MainWindow_SettingsMenuText;
            mnuSettings.Click += new EventHandler(mnuSettings_Click);

            mnuShowITunes.Text = Properties.Resources.MainWindow_ShowItunesMenuText;
            mnuShowITunes.Click += new EventHandler(mnuShowITunes_Click);

            mnuStop.Text = Properties.Resources.MainWindow_StopMenuText;
            mnuStop.Click += new EventHandler(mnuStop_Click);

            mnuNotifier.Items.Add(mnuShowITunes);
            mnuNotifier.Items.Add(mnuSeparator1);

            mnuNotifier.Items.Add(mnuPlayPause);
            mnuNotifier.Items.Add(mnuStop);
            mnuNotifier.Items.Add(mnuNextTrack);
            mnuNotifier.Items.Add(mnuPreviousTrack);
            mnuNotifier.Items.Add(mnuSeparator2);

            mnuNotifier.Items.Add(mnuSettings);
            mnuNotifier.Items.Add(mnuAbout);
            mnuNotifier.Items.Add(mnuSeparator3);

            mnuNotifier.Items.Add(mnuExit);

            mainNotifer = new System.Windows.Forms.NotifyIcon();
            mainNotifer.Icon = Properties.Resources.ApplicationIcon;
            mainNotifer.ContextMenuStrip = mnuNotifier;
            mainNotifer.Visible = Settings.DefaultInstance.ShowNotifyIcon;
            mainNotifer.MouseClick += new System.Windows.Forms.MouseEventHandler(mainNotifer_MouseClick);
            mainNotifer.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(mainNotifer_MouseDoubleClick);
            #endregion
        }

		#endregion

		#region Event Handlers
		private void MainWindow_Loaded(object sender, RoutedEventArgs e)
		{
            Win32.HideWindowFromCtrlAltDelete(this);
			this.Opacity = 0;
			this.Hide();
			_VisibilityStatus = VisibilityStatusEnum.Hidden;

			this.Top = (System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Bottom - this.Height);
			this.Left = (System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Right - this.Width);            
		}
		private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Controller.DefaultInstance.Dispose();
		}

		private void MainWindow_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
		{
			Debug.WriteLine(string.Format("{0} - MouseEnter fired", DateTime.Now.Ticks));

			if( _VisibilityStatus != VisibilityStatusEnum.ForceHiding )
				AnimateShow();
		}
		private void MainWindow_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
		{
			Debug.WriteLine(string.Format("{0} - MouseLeave fired", DateTime.Now.Ticks));

			if( _HidingTimer != null && !_HidingTimer.IsEnabled )
				_HidingTimer.Start();
		}

        private void mainNotifer_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if( e.Button == System.Windows.Forms.MouseButtons.Left )
            {
                Controller.DefaultInstance.NextTrack();
                Controller.DefaultInstance.Play();
            }
        }
        private void mainNotifer_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if( e.Button == System.Windows.Forms.MouseButtons.Left )
            {
                Controller.DefaultInstance.PlayPause();
            }
        }

        private void mnuStop_Click(object sender, EventArgs e)
        {
            Controller.DefaultInstance.StopPlaying();
        }
        private void mnuShowITunes_Click(object sender, EventArgs e)
        {
            Controller.DefaultInstance.ShowITunes();
        }
        private void mnuSettings_Click(object sender, EventArgs e)
        {
            ShowSettingsWindow();
        }
        private void mnuPreviousTrack_Click(object sender, EventArgs e)
        {
            Controller.DefaultInstance.PreviousTrack();
        }
        private void mnuPlayPause_Click(object sender, EventArgs e)
        {
            Controller.DefaultInstance.PlayPause();
        }
        private void mnuNextTrack_Click(object sender, EventArgs e)
        {
            Controller.DefaultInstance.NextTrack();
        }
        private void mnuExit_Click(object sender, EventArgs e)
        {
            CloseApplication();
        }
        private void mnuAbout_Click(object sender, EventArgs e)
        {
            ShowAboutWindow();
        }

		private void btnHideTrackInfo_Click(object sender, RoutedEventArgs e)
		{
			Debug.WriteLine(string.Format("{0} - btnHideTrackInfo_Click fired", DateTime.Now.Ticks));
			AnimateHide(true);
		}

		private void HidingTimer_Elapsed(object sender, EventArgs e)
		{
			_HidingTimer.Stop();

			if( _VisibilityStatus == VisibilityStatusEnum.Visible )
				AnimateHide();
		}
		private void FadeInStoryBoard_Completed(object sender, EventArgs e)
		{
			_VisibilityStatus = VisibilityStatusEnum.Visible;
			if( _HidingTimer != null ) //Restart hiding timer.
			{
				_HidingTimer.Stop();
				_HidingTimer.Start();
			}
		}
		private void FadeOutStoryBoard_Completed(object sender, EventArgs e)
		{
			if( _VisibilityStatus == VisibilityStatusEnum.Hiding )
			{
				this.Hide();
				_VisibilityStatus = VisibilityStatusEnum.Hidden;
			}
		}

		private void trackRating_RatingChanged(object sender, RoutedEventArgs e)
		{
			Controller.DefaultInstance.UpdateCurrentTrackRating(trackRating.RatingValue);
		}

		private void SettingsWindow_Closed(object sender, EventArgs e)
		{
			_SettingsWindow.Closed -= new EventHandler(SettingsWindow_Closed);
			_SettingsWindow = null;
		}
        private void AboutWindow_Closed(object sender, EventArgs e)
        {
            _AboutWindow.Closed -= new EventHandler(AboutWindow_Closed);
            _AboutWindow = null;
        }

		private void Controller_NewCommandReceived(object sender, NewCommandReceivedEventArgs e)
		{
			if( !this.Dispatcher.CheckAccess() )
			{
				this.Dispatcher.Invoke(new EventHandler<NewCommandReceivedEventArgs>(this.Controller_NewCommandReceived), sender, e);
				return;
			}

			switch( e.Command )
			{
				case InterfaceCommand.Quit:
                    CloseApplication((bool)e.Tag);
					break;
				case InterfaceCommand.NewTrackStarted:
					ShowTrackInformation(e.Tag);
					break;
				case InterfaceCommand.PlaybackChanged:
					if( Settings.DefaultInstance.ShowPlaybackStatus )
						PlaybackChanged((string)e.Tag);
					break;
				case InterfaceCommand.RatingChanged:
					ShowTrackInformation(Controller.DefaultInstance.CurrentTrack);
					break;
				case InterfaceCommand.ToggleTrackInfoVisibility:
					if( _VisibilityStatus == VisibilityStatusEnum.Visible || _VisibilityStatus == VisibilityStatusEnum.Showing )
						AnimateHide();
					else
						ShowTrackInformation(e.Tag);
					break;
				case InterfaceCommand.ShowSettingsWindow:
					ShowSettingsWindow();
					break;
				case InterfaceCommand.ShowQuickSelectWindow:
					ShowQuickSelectWindow();
                    break;
                case InterfaceCommand.ShowAboutWindow:
                    ShowAboutWindow();
					break;
			}
		}
		#endregion

		#region Methods
		private void ShowTrackInformation(object iTrack)
		{
			string artworkTempPath = System.IO.Path.GetTempPath() + "iControlCurrentTrackArtwork.temp";

			IITTrack trackInfo = (IITTrack)iTrack;

            if( trackInfo == null )
                return;

			this.lblTrackTitle.Content = trackInfo.Name;
			this.lblTrackAlbum.Content = trackInfo.Album;
			this.lblTrackArtist.Content = trackInfo.Artist;
			this.trackRating.RatingValue = (int)(trackInfo.Rating / 20);

			BitmapImage albumArtwork = null;

			foreach( IITArtwork artwork in trackInfo.Artwork )
			{
				artwork.SaveArtworkToFile(artworkTempPath);

				var memStream = new System.IO.MemoryStream();
				albumArtwork = new BitmapImage();
				var originalBitmap = Bitmap.FromFile(artworkTempPath);

				originalBitmap.Save(memStream, System.Drawing.Imaging.ImageFormat.Png);
				originalBitmap.Dispose();

				albumArtwork.CacheOption = BitmapCacheOption.OnLoad;
				albumArtwork.BeginInit();
				albumArtwork.StreamSource = memStream;
				albumArtwork.EndInit();

				break;
			}

			if( albumArtwork != null )
				this.imgAlbumArtwork.Source = albumArtwork;
			else
				this.imgAlbumArtwork.Source = Shared.ConvertToBitmapSource(Properties.Resources.NoArtworkImage);

			if( pnlPlaybackInfo.Visibility == Visibility.Visible )
			{
				pnlPlaybackInfo.Visibility = Visibility.Collapsed;
				pnlTrackInfo.Visibility = Visibility.Visible;
				imgAlbumArtwork.Visibility = Visibility.Visible;
			}

			this.AnimateShow();
		}
		private void PlaybackChanged(string tag)
		{
			pnlPlaybackInfo.Visibility = Visibility.Visible;
			pnlTrackInfo.Visibility = Visibility.Collapsed;
			imgAlbumArtwork.Visibility = Visibility.Collapsed;

			if( tag == "STOPPED" )
				lblPlaybackInfo.Content = Properties.Resources.PlaybackStopped;
			else
				lblPlaybackInfo.Content = Properties.Resources.PlaybackPaused;

			AnimateShow();
		}
		private void ShowSettingsWindow()
		{
			if( _SettingsWindow == null )
			{
				_SettingsWindow = new SettingsWindow();
				_SettingsWindow.Closed += new EventHandler(SettingsWindow_Closed);
				_SettingsWindow.Show();
			}
			else
			{
				_SettingsWindow.Show();
			}
		}
		private void ShowQuickSelectWindow()
		{
			if( _QuickSelectWindow == null )
			{
				_QuickSelectWindow = new QuickSelectWindow();				
			}

			_QuickSelectWindow.Show();
		}
        private void ShowAboutWindow()
        {
            if( _AboutWindow == null )
            {
                _AboutWindow = new AboutWindow();
                _AboutWindow.Closed += new EventHandler(AboutWindow_Closed);
                _AboutWindow.Show();
            }
            else
            {
                _AboutWindow.Show();
            }
        }
        private static void CloseApplication()
        {
            CloseApplication(true);
        }
        private static void CloseApplication(bool confirm)
        {
            if( _ClosingApplication )
                return;

            _ClosingApplication = true;

            if( confirm )
            {
                MessageBoxResult result = MessageBox.Show(Properties.Resources.CloseITunesConfirmation, "iControl", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);

                if( result == MessageBoxResult.Yes )
                    Controller.DefaultInstance.CloseITunes();
            }
            
            Application.Current.Shutdown();
        }

		private void AnimateShow()
		{
			_VisibilityStatus = VisibilityStatusEnum.Showing;
			this.Show();

			((DoubleAnimation)_FadeInStoryBoard.Children[0]).Duration = TimeSpan.FromMilliseconds(Settings.DefaultInstance.FadeInDuration);
			_FadeInStoryBoard.Begin(this);
		}
		private void AnimateHide()
		{
			AnimateHide(false);
		}
		private void AnimateHide(bool force)
		{
            
			if( force || !this.IsMouseOver )
			{
				_VisibilityStatus = (force) ? VisibilityStatusEnum.ForceHiding : VisibilityStatusEnum.Hiding;

				((DoubleAnimation)_FadeInStoryBoard.Children[0]).Duration = TimeSpan.FromMilliseconds(Settings.DefaultInstance.FadeOutDuration);
				_FadeOutStoryBoard.Begin(this);
			}			
		}
		#endregion       
	}
}

